

/* a few ideas to help you with the VM
 *
 * this is all UNTESTED and isn't a required approach; 
 * just is here to get you thinking! 
 *
 * 	-Ryanne
 */

struct vm_State {
	int regs [8];
	int IP;
};

/* function pointer for functions implementing operations */
typedef int (* vm_Opfxn) (struct vm_State *, union vm_Value, union vm_Value);

/* an instruction has an operation and two arguments */
struct vm_Instruction {
	vm_Opfxn fxn;
	union vm_Value a;
	union vm_Value b;
};

/* a program is an array of instructions */
struct vm_Program {
	struct vm_Instruction *insts;
	int ninsts;
};

/* parses:
 * 	MOV Ra Rb
 * 	MOV Ra x
 */
int vm_parseMOV (struct vm_Instruction *inst, struct token_list *ll) {
	struct token dest = token_popfront (ll);
	struct token source = token_popfront (ll);

	inst->a = dest.val;
	inst->b = source.val;

	if (dest.type != REGISTER) {
		fprintf (stderr,  "expected REGISTER for first argument to MOV");
		return -1;
	}

	if (source.type == REGISTER) {
		inst->fxn = vm_MOV_Ra_Rb;
	}
	else if (source.type == INTEGER) {
		inst->fxn = vm_MOV_Ra_x;
	}
	else {
		fprintf (stderr, "expected INTEGER or REGISTER for second argument to MOV"); 
		return -1;
	}

	return 0;
}

int vm_parseinstruction (struct vm_Instruction *inst, struct token_list *ll) {
	struct token op = token_popfront (ll);

	if (token.type != OPCODE) {
		fprintf (stderr, "expected OPCODE as first token in an instruction");

		return -1;
	}

	if (token.val.op == MOV) {
		return vm_parseMOV (inst, ll);
	}
	else if (token.val.op == ADD) {
		return vm_parseADD (inst, ll);
	}

	fprintf (stderr, "unknown OPCODE");
	
	return -1;
}

/* implements the MOV Ra Rb instruction */
int vm_MOV_Ra_Rb (struct vm_State *vm, union vm_Value a, union vm_Value b) {
	vm->regs [(int) a.r] = vm->regs [(int) b.r];

	return 0;
}

/*implements the MOV Ra x instruction */
int vm_MOV_Ra_x (struct vm_State *vm, union vm_Value a, union vm_Value b) {
	vm->regs [(int) a.r] = b.i;
}


